package com.ddkj.netty.server.socket.chargingServer;

import cn.hutool.core.util.HexUtil;
import com.ddkj.netty.Setting;
import com.ddkj.netty.redis.RedisUtil;
import com.ddkj.netty.server.TCPAddress;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.AttributeKey;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * TCPByteHandler
 */
public class ChargingServerHandler extends ChannelInboundHandlerAdapter {

    private static final Log log = LogFactory.getLog(ChargingServerHandler.class);

    //会话
    public static final AttributeKey<TCPAddress> KEY = AttributeKey.valueOf(Setting.SOCKET_DDKJ_CHARGING_NETTY);

    //存储channel
    public static Map<String, Channel> channelMap = new HashMap<>();

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {

        TCPAddress tcpAddress = new TCPAddress(ctx.channel());
        log.info(Setting.CHARGING_SERVER_NAME + "client_ip--> " + tcpAddress.getClientIP() + " 【上线】");
        ctx.channel().attr(KEY).set(tcpAddress);

        //存储channel
        channelMap.put(tcpAddress.getClientIP(), ctx.channel());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        ByteBuf buf = (ByteBuf) msg;
        byte[] receiveMsgBytes = new byte[buf.readableBytes()];
        buf.readBytes(receiveMsgBytes);

        //将数据十六进制转换为字符串
        String message = HexUtil.encodeHexStr(receiveMsgBytes).toUpperCase();

        //返回数据
        String data = null;

        //获取用户数据
        TCPAddress tcpAddress = ctx.channel().attr(KEY).get();
        String clientIP = tcpAddress.getClientIP();//ip

        //后台服务id
        String serverId = Setting.CHARGING_SERVER_CLOUD;

        //读取数据
        log.info("【----------------------------------------------------】" + Setting.CHARGING_SERVER_NAME + "client_ip--> " + clientIP + " 【处理后数据】" + message);

        //客户端id
        String seat_code = message.contains(serverId) ? serverId : message.substring(0, 8);

        //功能code
        String charging_communication_code = seat_code != null ? message.substring(8, 10) : message.substring(serverId.length(), serverId.length() + 2);

        //是否向客户端发送标识
        if (message.contains(Setting.CHARGING_BEAT_IDENTIFICATION)) {
            String[] identificationSplit = message.split(Setting.CHARGING_BEAT_IDENTIFICATION);

            //获取接收者
            String recip = RedisUtil.get(Setting.DDKJ_NETTY_CHARGING_SOCKET_HEADER + identificationSplit[0]);

            if (recip == null) {
                ctx.channel().writeAndFlush("client not online!!");
                return;
            }
            sendMessage(channelMap.get(recip), identificationSplit[1]);
            return;
        }

        //缓存数据判断
        String client_ip = RedisUtil.get(Setting.DDKJ_NETTY_CHARGING_SOCKET_HEADER + seat_code);

        //缓存数据校验
        if (client_ip == null || !client_ip.equals(clientIP)) {
            //存储数据,清缓存时所用
            RedisUtil.set(Setting.DDKJ_NETTY_CHARGING_SOCKET_HEADER + seat_code, clientIP);
            RedisUtil.set(clientIP, Setting.DDKJ_NETTY_CHARGING_SOCKET_HEADER + seat_code);
        }

        //code 05 心跳
        if (charging_communication_code.equals(Setting.CHARGING_IDENTIFICATION)) {
            log.info(Setting.CHARGING_SERVER_NAME + " ---->" + "【心跳】 ---->" + "【数据】 ---->" + message);
            String restr = String.format(Setting.CHARGING_BEAT_SUCCESS_REQUEST, seat_code == null ? serverId : seat_code, "55", "01");
            sendMessage(ctx.channel(), restr + makeChecksum(restr));
            return;
        }


        //其他业务，转发到后台处理
        String recip = RedisUtil.get(Setting.DDKJ_NETTY_CHARGING_SOCKET_HEADER + serverId);

        if (recip != null) {
            //向后台服务器返回数据
            sendMessage(channelMap.get(recip), message);
            return;
        }
        sendMessage(ctx.channel(), "000000000000000000000000000001");
        return;
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        TCPAddress tcpAddress = new TCPAddress(ctx.channel());
        String clientIP = tcpAddress.getClientIP();
        removeIP(clientIP);
        log.info(Setting.CHARGING_SERVER_NAME + "client_ip--> " + clientIP + " 【下线】");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

        log.error("异常消息为-------->" + cause);
    }


    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
        ctx.flush();
    }

    /**
     * 发送消息
     */
    public void sendMessage(Channel channel, String message) {
        ByteBuf encoded = channel.alloc().buffer(4 * message.length());
        encoded.writeBytes(HexUtil.decodeHex(message));
        channel.write(encoded);
        channel.flush();
    }

    //清除数据
    protected void removeIP(String ipURI) {

        String whos = RedisUtil.get(ipURI);

        if (whos != null) {
            RedisUtil.remove(whos);
        }
        RedisUtil.remove(ipURI);
        //清空存储Map
        channelMap.remove(ipURI);
    }


    /**
     * 累加和校验
     *
     * @param data 校验数据
     * @return
     */
    public static String makeChecksum(String data) {
        if (data == null || data.equals("")) {
            return "";
        }
        int total = 0;
        int len = data.length();
        int num = 0;
        while (num < len) {
            String s = data.substring(num, num + 2);
            // System.out.println(s);
            total += Integer.parseInt(s, 16);
            num = num + 2;
        }
        /**
         * 用256求余最大是255，即16进制的FF
         */
        int mod = total % 256;
        String hex = Integer.toHexString(mod);
        len = hex.length();
        // 如果不够校验位的长度，补0,这里用的是两位校验
        if (len < 2) {
            hex = "0" + hex;
        }
        return hex;
    }

}
